
function game2048(){
    let len=4;
    let size=20;
    let margin=4;
    let score=0;
    let winNum=16;
    let isGameOver=false;

    // 实例化视图对象
    let view = new View(len,size,margin)
    let board = new Board(len)

    view.init()
    board.init()

    board.onGenerate=function(e){
        // console.log(e);
        view.addNum(e.x,e.y,e.num,true)
    }

    board.generate()
    board.generate()

    board.onMove=function(e){
        view.move(e.from,e.to)

        if(e.to.num>e.from.num){
            score+=e.to.num
            view.updateScore(score,e.to.num)
        }

        // 游戏胜利
        if(e.to.num>=winNum){
            // alert('大牛！你成功了！')
            isGameOver=true
            view.win()
        }

        // 声音效果
        let rnd=Math.floor(Math.random()*11)+1
        $('#sound').attr({
            src:`sound/${rnd}.mp3`
        })
    }

    board.onMoveComplete=function(arr){
        setTimeout(function(){
            view.updateView(arr)
        },200)

        setTimeout(function(){
            board.generate()
        },300)

        // 游戏结束
        if(!board.canMove()){
            // alert('游戏结束，你的分数是'+score)
            isGameOver=true
            view.over(score)
        }
    }

    $(document).keydown(function(e) {

        if(isGameOver){
            return false
        }

        switch (e.which) {
          case 37: board.moveLeft();  break;
          case 38: board.moveUp();    break;
          case 39: board.moveRight(); break;
          case 40: board.moveDown();  break;
        }
    });

    // 实现触控
    let startx,endx,starty,endy
    document.addEventListener('touchstart',function(e){
        startx=e.touches[0].pageX
        starty=e.touches[0].pageY
    })

    document.addEventListener('touchend',function(e){
        endx=e.changedTouches[0].pageX
        endy=e.changedTouches[0].pageY

        if(isGameOver){return false}

        // 判断在x轴还是y轴移动
        if(Math.abs(endx-startx)>Math.abs(endy-starty)){// x轴移动
            if((endx-startx)>0){board.moveRight();}// 向右移动
            else{board.moveLeft();}// 向左移动
        }
        else{// y轴移动
            if((endy-starty)>0){board.moveDown();}// 向下移动
            else{board.moveUp();} // 向上移动
        }
    })
    

    $('#game_restart').on('click',function(){
        restart()
    })

    function restart(){
        score=0
        view.updateScore(score)
        $('#game_over').addClass('game-hide')
        $('.game-num').remove()
        board.init()
        view.init()
        board.generate()
        board.generate()
        isGameOver=false

    }
}


// 控制游戏视图的类

class View{
    constructor(len,size,margin){
        this.len=len;
        this.size=size;
        this.margin=margin

        this.cellcon=$('#cell-con')
        this.numcon=$('#num-con')
    }

    // 计算位置的方法
    getPos(n){
        return this.margin+n*(this.size+this.margin)
    }

    init(){
        for(let x=0;x<this.len;x++){
            for(let y=0;y<this.len;y++){
                let cell=$('<div>').addClass('game-cell').css({
                    top:this.getPos(x)+'%',
                    left:this.getPos(y)+'%'
                })
                this.cellcon.append(cell)
            }
        }
    }

    addNum(x,y,n,flag){
        let num = $('<div>').addClass(`game-num game-num-${n}`).attr('id',`cell-${x}-${y}`).css({
            top:this.getPos(x)+'%',
            left:this.getPos(y)+'%'
        }).text(n)
        if(flag){
            num.addClass('game-num-show')
        }
        this.numcon.append(num)
    }

    move(from,to){
        $(`#cell-${from.x}-${from.y}`).animate({
            top:this.getPos(to.x)+'%',
            left:this.getPos(to.y)+'%'
        },150)
    }

    updateView(arr){
        console.log(arr);
        $('.game-num').remove()

        for(let x=0;x<this.len;x++){
            for(let y=0;y<this.len;y++){
                if(arr[x][y]!=0){
                    this.addNum(x,y,arr[x][y])
                }
            }
        }
    }

    updateScore(score,addScore){
        $('#game_score').text(score)

        if(addScore){
            $('.game_score_add').remove()
            let add=$('<span>').text('+'+addScore).addClass('game_score_add')
            $('.game-score').append(add)
        }
    }

    win(){
        $('#game_over').removeClass('game-hide')
        $('#game_over_info p').text('恭喜，你获胜了！')
    }

    over(score){
        $('#game_over').removeClass('game-hide')
        $('#game_over_info p').text('你本次的得分是：'+score)
    }


}


// 控制游戏数值的类
class Board{
    constructor(len){
        this.len=len
        this.arr=[]
    }
    init(){
        for(let x=0;x<this.len;x++){
            this.arr[x]=[]
            for(let y=0;y<this.len;y++){
                this.arr[x][y]=0
            }
        }
        console.log(this.arr);
    }
    // 自定义事件
    onGenerate(){}
    onMove(){}
    onMoveComplete(){}

    generate(){
        let empty=[]
        for(let x=0;x<this.len;x++){
            for(let y=0;y<this.len;y++){
                if(this.arr[x][y]==0){
                    empty.push({x:x,y:y})
                }
            }
        }
        
        let rnd=Math.floor(Math.random()*empty.length);
        // console.log(empty,rnd);
        let one = empty[rnd]
        this.arr[one.x][one.y]=Math.random()<0.5 ? 2 : 4;

        // console.log(this.arr);
        this.onGenerate({x:one.x,y:one.y,num:this.arr[one.x][one.y]})
    }
    // 左移
    moveLeft(){
        // let isMoved=false
        // 从上到下，从左到右
        for(let x=0;x<this.len;x++){
            for(let y=0;y<this.len;y++){
                // 从 y + 1 位置开始，向右查找
                for(let next=y+1;next<this.len;next++){
                    // 如果 next 单元格是 0，找下一个不是 0 的单元格
                   if(this.arr[x][next]==0){
                    continue
                   }

                   else{
                        // 如果 y 数字是 0，则将 next 移动到 y 位置，然后将 y 减 1 重新查找
                        if(this.arr[x][y]==0){
                            this.arr[x][y]=this.arr[x][next]
                            this.onMove({
                                from:{x:x,y:next,num:this.arr[x][next]},
                                to:{x:x,y:y,num:this.arr[x][y]}
                            })

                            this.arr[x][next]=0
                            // isMoved=true
                            y--
                        }
                        // 如果 y 与 next 单元格数字相等，则将 next 移动并合并给 y
                        else if(this.arr[x][y]==this.arr[x][next]){
                            this.arr[x][y]+=this.arr[x][next]
                            this.onMove({
                                from:{x:x,y:next,num:this.arr[x][next]},
                                to:{x:x,y:y,num:this.arr[x][y]}
                            })

                            this.arr[x][next]=0
                            // isMoved=true
                        }
                   }
                   break
                }
            }
        }
        console.log(this.arr);
        this.onMoveComplete(this.arr)
    }

    // 右移
    moveRight(){
        // let isMoved=false
        for(let x=0;x<this.len;x++){
            for(let y=this.len-1;y>=0;y--){
                for(let next=y-1;next>=0;next--){
                   if(this.arr[x][next]==0){
                    continue
                   }

                   else{
                        if(this.arr[x][y]==0){
                            this.arr[x][y]=this.arr[x][next]
                            this.onMove({
                                from:{x:x,y:next,num:this.arr[x][next]},
                                to:{x:x,y:y,num:this.arr[x][y]}
                            })
                            this.arr[x][next]=0
                            // isMoved=true
                            y++
                        }
                        else if(this.arr[x][y]==this.arr[x][next]){
                            this.arr[x][y]+=this.arr[x][next]
                            this.onMove({
                                from:{x:x,y:next,num:this.arr[x][next]},
                                to:{x:x,y:y,num:this.arr[x][y]}
                            })
                            this.arr[x][next]=0
                            // isMoved=true
                        }
                   }
                   break
                }
            }
        }
        console.log(this.arr);
        this.onMoveComplete(this.arr)
    }
    // 上移
    moveUp(){
        // let isMoved=false
        for(let y=0;y<this.len;y++){
            for(let x=0;x<this.len;x++){
                for(let next=x+1;next<this.len;next++){
                   if(this.arr[next][y]==0){
                    continue
                   }

                   else{
                        if(this.arr[x][y]==0){
                            this.arr[x][y]=this.arr[next][y]
                            this.onMove({
                                from:{x:next,y:y,num:this.arr[next][y]},
                                to:{x:x,y:y,num:this.arr[x][y]}
                            })
                            this.arr[next][y]=0
                            // isMoved=true
                            x--
                        }
                        else if(this.arr[x][y]==this.arr[next][y]){
                            this.arr[x][y]+=this.arr[next][y]
                            this.onMove({
                                from:{x:next,y:y,num:this.arr[next][y]},
                                to:{x:x,y:y,num:this.arr[x][y]}
                            })
                            this.arr[next][y]=0
                            // isMoved=true
                        }
                   }
                   break
                }
            }
        }
        console.log(this.arr);
        this.onMoveComplete(this.arr)
    }
    // 下移
    moveDown(){
        // let isMoved=false
        for(let y=0;y<this.len;y++){
            for(let x=this.len-1;x>=0;x--){
                for(let next=x-1;next>=0;next--){
                   if(this.arr[next][y]==0){
                    continue
                   }

                   else{
                        if(this.arr[x][y]==0){
                            this.arr[x][y]=this.arr[next][y]
                            this.onMove({
                                from:{x:next,y:y,num:this.arr[next][y]},
                                to:{x:x,y:y,num:this.arr[x][y]}
                            })
                            this.arr[next][y]=0
                            // isMoved=true
                            x++
                        }
                        else if(this.arr[x][y]==this.arr[next][y]){
                            this.arr[x][y]+=this.arr[next][y]
                            this.onMove({
                                from:{x:next,y:y,num:this.arr[next][y]},
                                to:{x:x,y:y,num:this.arr[x][y]}
                            })
                            this.arr[next][y]=0
                            // isMoved=true
                        }
                   }
                   break
                }
            }
        }
        console.log(this.arr);
        this.onMoveComplete(this.arr)
    }

    canMove(){
        // 遍历整个数组，如果没有为0的，相邻之间没有相等的数字，则表示不能继续移动
        for(let x=0;x<this.len;x++){
            for(let y=0;y<this.len;y++){
                if(this.arr[x][y]==0){
                    return true
                }
                let cur=this.arr[x][y]
                let right=this.arr[x][y+1]
                let down=this.arr[x+1]?this.arr[x+1][y]:null

                if(cur==right||cur==down){
                    return true
                }
            }
        }
        return false
    }

}